#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "widgets/objectview.h"
#include "editors/editormanager.h"
#include <QDockWidget>
#include <QCloseEvent>
#include <QFileDialog>
#include <QMessageBox>
#include <QStackedWidget>

#include "application.h"
#include "document.h"
#include "gameobjects/abstractobject.h"
#include "gameobjects/graphicsobject.h"
#include "gameobjects/animation.h"
#include "gameobjects/texture.h"
#include "editors/abstracteditor.h"
#include "editors/physicssimulatordialog.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setupToolbar();

    setAttribute(Qt::WA_DeleteOnClose);

    m_editorsStackedWidget = new QStackedWidget;
    setCentralWidget(m_editorsStackedWidget);

    m_objectView = new ObjectView(this);
    QDockWidget* pDock = new QDockWidget("Object View", this);
    pDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    pDock->setWidget(m_objectView);
    addDockWidget(Qt::LeftDockWidgetArea, pDock);
    pDock->setFixedWidth(200);

    updateGUI();
    updateMenuCreateObject(QPointer<AbstractObject>());
}

MainWindow::~MainWindow()
{
    delete ui;
}

QPointer<ObjectView> MainWindow::objectView() const
{
    return m_objectView;
}

QPointer<QStackedWidget> MainWindow::editorsStackedWidget() const
{
    return m_editorsStackedWidget;
}

QPointer<QMenu> MainWindow::objectsMenu() const
{
    return ui->menuObjects;
}

bool MainWindow::askToSave()
{
    QMessageBox::StandardButton answer = QMessageBox::question(this, "Closing current document",
        "Document was modified, do you want to save your changes?", QMessageBox::Yes | QMessageBox::No);

    return (answer == QMessageBox::Yes);
}

bool MainWindow::attemptToSaveDocument(QPointer<Document> doc)
{
    bool bResult = false;

    if(doc->currentFileName().isEmpty())
    {
        bResult = saveAs();
    }
    else
    {
        bResult = save();
    }

    return bResult;
}

bool MainWindow::save()
{
    return Application::app().saveDocument();
}

bool MainWindow::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save Project As", QString(), "*.gef");

    if(!fileName.isEmpty())
    {
        Application::app().document()->setCurrentFileName(fileName);
        return save();
    }

    return false;
}

void MainWindow::setupToolbar()
{
    ui->mainToolBar->addAction(ui->actionNew_Project);
    ui->mainToolBar->addAction(ui->actionOpen);
    ui->mainToolBar->addAction(ui->actionSave_As);
    ui->mainToolBar->addAction(ui->actionSave);
    ui->mainToolBar->addAction(ui->actionClose_Project);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(ui->actionNew_Graphics_Object);
    ui->mainToolBar->addAction(ui->actionNew_Animation);
    ui->mainToolBar->addAction(ui->actionNew_Texture);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(ui->actionDeleteObject);
}

void MainWindow::updateGUI()
{
    QPointer<Document> doc = Application::app().document();

    ui->actionSave_As->setEnabled(doc != 0);
    ui->actionSave->setEnabled(doc !=0 && doc->isModified() && !doc->currentFileName().isEmpty());
    ui->actionClose_Project->setEnabled(doc != 0);

    m_objectView->setEnabled(doc != 0);
    //ui->menuObjects->setEnabled(doc != 0);
}

void MainWindow::updateMenuCreateObject(QPointer<AbstractObject> selectedObject)
{
    QPointer<Document> doc = Application::app().document();

    ui->actionNew_Graphics_Object->setEnabled(doc != 0);
    ui->actionNew_Animation->setEnabled(doc != 0 && selectedObject != 0
            && !qobject_cast<Texture*>(selectedObject));
    ui->actionNew_Texture->setEnabled(doc != 0 && selectedObject != 0
            && qobject_cast<Texture*>(selectedObject) == 0);
    ui->actionDeleteObject->setEnabled(doc != 0 && selectedObject != 0);
}

void MainWindow::closeEvent(QCloseEvent *pEvent)
{

}

void MainWindow::on_actionNew_Project_triggered()
{
    QPointer<Document> doc = Application::app().document();

    if(!doc)
    {
        Application::app().createDocument();
    }
    else
    {
        bool toCloseAndCreateNew = true;

        if(askToSave())
        {
            toCloseAndCreateNew = attemptToSaveDocument(doc);
        }

        if(toCloseAndCreateNew)
        {
            Application::app().closeDocument();
            Application::app().createDocument();
        }
    }

    updateGUI();
}

void MainWindow::on_actionOpen_triggered()
{
    QPointer<Document> doc = Application::app().document();

    if(!doc)
    {
        QString fileName = QFileDialog::getOpenFileName(this, "Open Project", QString(), "*.gef");

        if(!fileName.isEmpty())
        {
            Application::app().loadDocument(fileName);
        }
    }
    else
    {
        bool toCloseAndLoadDocument = true;

        if(askToSave())
        {
            toCloseAndLoadDocument = attemptToSaveDocument(doc);
        }

        if(toCloseAndLoadDocument)
        {
            QString fileName = QFileDialog::getOpenFileName(this, "Open Project", QString(), "*.gef");

            if(!fileName.isEmpty())
            {
                Application::app().closeDocument();
                Application::app().loadDocument(fileName);
            }
        }
    }

    updateGUI();
}

void MainWindow::on_actionSave_As_triggered()
{
    saveAs();
    updateGUI();
}

void MainWindow::on_actionSave_triggered()
{
    if(Application::app().document()->currentFileName().isEmpty())
    {
        saveAs();
    }
    else
    {
        save();
    }

    updateGUI();
}

void MainWindow::on_actionExit_triggered()
{
    close();
}

void MainWindow::on_actionClose_Project_triggered()
{
    QPointer<Document> doc = Application::app().document();

    if(doc->isModified())
    {
        bool toCloseAndLoadDocument = true;

        if(askToSave())
        {
            toCloseAndLoadDocument = attemptToSaveDocument(doc);
        }

        if(toCloseAndLoadDocument)
        {
            Application::app().closeDocument();
        }
    }
    else
    {
        Application::app().closeDocument();
    }

    updateGUI();
}

void MainWindow::on_actionNew_Graphics_Object_triggered()
{
    QPointer<Document> doc = Application::app().document();
    Q_ASSERT(doc);

    static int id = -1;
    ++id;

    QString name = QString("GraphicsObject%1").arg(id);
    QPointer<GraphicsObject> obj = doc->createGraphicsObject(name);
}

void MainWindow::on_actionNew_Animation_triggered()
{
    QPointer<Document> doc = Application::app().document();
    Q_ASSERT(doc);

    static int id = -1;
    ++id;

    QPointer<GraphicsObject> parentObject;

    if(QPointer<GraphicsObject> go = qobject_cast<GraphicsObject*>(doc->currentObject()))
    {
        parentObject = go;
    }
    else if(QPointer<Animation> anim = qobject_cast<Animation*>(doc->currentObject()))
    {
        parentObject = qobject_cast<GraphicsObject*>(anim->parentObject());
    }
    else
    {
        Q_ASSERT(false);
    }

    QString name = QString("Animation%1").arg(id);
    doc->createAnimation(name, parentObject);
}

void MainWindow::on_actionNew_Texture_triggered()
{
    QPointer<Document> doc = Application::app().document();
    Q_ASSERT(doc);

    QPointer<AbstractObject> selObj = doc->currentObject();

    if(QPointer<Texture> tex = qobject_cast<Texture*>(selObj))
    {
        // just check once again adding texture to texture
        // (that should be prevented in disabling menu item for adding tex to tex)
        Q_ASSERT(false);
    }
    else
    {
        QPointer<Texture> existingTex;

        if(QPointer<GraphicsObject> go = qobject_cast<GraphicsObject*>(selObj))
        {
            existingTex = go->texture();
        }
        else if(QPointer<Animation> anim = qobject_cast<Animation*>(selObj))
        {
            existingTex = anim->texture();
        }

        if(existingTex)
        {
            QMessageBox::StandardButton answer = QMessageBox::question(this, "Adding texture",
                "Animation already has texture? Do you want to replace existing texture?",
               QMessageBox::Yes | QMessageBox::No);

            if(answer == QMessageBox::No)
            {
                return;
            }
            else
            {
                doc->deleteObject(qobject_cast<AbstractObject*>(existingTex));
            }
        }

        static int id = -1;
        ++id;

        QString name = QString("Texture%1").arg(id);
        QPointer<Texture> newTex = doc->createTexture(name, selObj);
    }
}

void MainWindow::on_actionPhysicsSimulator_triggered()
{
    PhysicsSimulatorDialog dlg(this);
    dlg.exec();
}

void MainWindow::onCurrentFilenameChanged(QString fileName)
{
    QString title = fileName.isEmpty() ? "Untitled" : fileName;
    setWindowTitle(QString("%1[*] - Editor").arg(title));
}

void MainWindow::on_actionDeleteObject_triggered()
{
    QPointer<Document> doc = Application::app().document();
    Q_ASSERT(doc);

    QPointer<AbstractObject> selObj = doc->currentObject();

    if(selObj)
    {
        doc->deleteObject(selObj);
    }
}

void MainWindow::onCurrentObjectChanged(QPointer<AbstractObject> currentObject)
{
    if(!currentObject)
    {
        Application::app().editorManager()->setActiveEditor("ProjectSummary");
    }
    else if(QPointer<GraphicsObject> obj = qobject_cast<GraphicsObject*>(currentObject))
    {
        Application::app().editorManager()->setActiveEditor("GraphicsObjectEditor");
    }
    else if(QPointer<Animation> obj = qobject_cast<Animation*>(currentObject))
    {
        Application::app().editorManager()->setActiveEditor("AnimationEditor");
    }
    else if(QPointer<Texture> obj = qobject_cast<Texture*>(currentObject))
    {
        Application::app().editorManager()->setActiveEditor("TextureEditor");
    }
}
